/**
 * Copyright (C) 2010 Maximilian Kalus.  All rights reserved.
 */

package com.boarbeard.lang.de;

import java.io.FileNotFoundException;
import java.lang.reflect.Field;
import java.util.List;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;

/**
 * @author mkalus
 *
 */
public class SpaceAlertContentProvider extends ContentProvider {
	// YOU HAVE TO CHANGE THIS:
	public static final String AUTHORITY = "com.boarbeard.lang.de";
	public static final Uri AUTHORIT_URI = Uri.parse("content://" + AUTHORITY);
	
	// YOU CAN CHANGE THIS:
	// File pattern type: either English or German/Czech
	// The difference lies in the threat files:
	// -> threat.mp3 vs threat_zone_blue.mp3 ...
	private static final boolean FILE_TYPE_ENGLISH = false;
	
	// URI types
	private static final int URI_LANGUAGE = 1;
	private static final int URI_STRINGS = 2;
	private static final int URI_FILELIST = 3;
	private static final int URI_FILELIST_ANNOUNCEMENT = 4;
	private static final int URI_FILELIST_DATA_TRANSFER = 5;
	private static final int URI_FILELIST_INCOMING_DATA = 6;
	private static final int URI_FILELIST_THREAT = 7;
	private static final int URI_FILELIST_WHITE_NOISE = 8;
	private static final int URI_MP3 = 9;
	
	// Content types
	public static final String CONTENT_TYPE = "vnd.android.cursor.dir/String";
	
	// reference on UriMatcher
	private static final UriMatcher URI_MATCHER;
	static {
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URI_MATCHER.addURI(AUTHORITY, "general/language", URI_LANGUAGE);
		URI_MATCHER.addURI(AUTHORITY, "text/*", URI_STRINGS);
		URI_MATCHER.addURI(AUTHORITY, "filelist/announcement/*", URI_FILELIST);
		URI_MATCHER.addURI(AUTHORITY, "filelist/data_transfer", URI_FILELIST);
		URI_MATCHER.addURI(AUTHORITY, "filelist/incoming_data", URI_FILELIST);
		URI_MATCHER.addURI(AUTHORITY, "filelist/threat/*/#/*/*", URI_FILELIST);
		URI_MATCHER.addURI(AUTHORITY, "filelist/white_noise/#", URI_FILELIST);
		URI_MATCHER.addURI(AUTHORITY, "mp3/*", URI_MP3);
	}
	
	private static final UriMatcher FILE_LIST_MATCHER;
	static {
		FILE_LIST_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		FILE_LIST_MATCHER.addURI(AUTHORITY, "filelist/announcement/*", URI_FILELIST_ANNOUNCEMENT);
		FILE_LIST_MATCHER.addURI(AUTHORITY, "filelist/data_transfer", URI_FILELIST_DATA_TRANSFER);
		FILE_LIST_MATCHER.addURI(AUTHORITY, "filelist/incoming_data", URI_FILELIST_INCOMING_DATA);
		FILE_LIST_MATCHER.addURI(AUTHORITY, "filelist/threat/*/#/*/*", URI_FILELIST_THREAT);
		FILE_LIST_MATCHER.addURI(AUTHORITY, "filelist/white_noise/#", URI_FILELIST_WHITE_NOISE);
	}
	
	/**
	 * Helper to get id from string
	 * @param variableName
	 * @param context
	 * @param c class
	 * @return
	 */
	public static int getResId(String variableName, Context context, Class<?> c) {
		try {
			Field idField = c.getDeclaredField(variableName);
			return idField.getInt(idField);
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}
	
	@Override
	public boolean onCreate() {
		return false; // dummy: always returns true
	}


	@Override
	public String getType(Uri uri) {
		return CONTENT_TYPE; //TODO: change type for MP3s
	}

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// check which kind of URIs where asked for
		String back;
		
		// match uris
		int matchedUriType = URI_MATCHER.match(uri);
		switch(matchedUriType) {
		case URI_LANGUAGE:
			// get language
			back = getLanguageName();
			break;
		case URI_STRINGS:
			// get name
			String part = uri.getPathSegments().get(1);
			back = getTextRepresentation(part);
			break;
		case URI_FILELIST:
			// file list by event type
			back = getFilelist(uri);
			break;
		case URI_MP3:
			return getMP3query(uri.getPathSegments().get(1));
		default:
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		
		// create a matrix cursor to return string
		MatrixCursor cursor = new MatrixCursor(new String[] {"data"}, 1);
		cursor.addRow(new Object[]{ back });
		return cursor;
	}
	
	/**
	 * get mp3 resource
	 * @param mp3file
	 * @return
	 */
	protected Cursor getMP3query(String mp3file) {
		MatrixCursor cursor = new MatrixCursor(new String[] {"_id", "_data"}, 1);
		cursor.addRow(new Object[]{ mp3file, "android.resource://" + AUTHORITY + "/raw/" + mp3file });
		return cursor;
	}
	
	/**
	 * Called by URI /general/language
	 * @return "long" language description like "English official"
	 */
	protected String getLanguageName() {
		return getContext().getString(R.string.language_name);
	}
	
	/**
	 * Called by URI /text/*
	 * @param identifier id (*) in the URI
	 * @return String name of event id or ERROR
	 */
	protected String getTextRepresentation(String identifier) {
		int id = getContext().getResources().getIdentifier("text." + identifier, "string", AUTHORITY);
		// does the resource exist?
		if (id == 0) return " ERROR: String " + identifier + " not found"; // return error
		else return getContext().getString(id); // return resource entry
	}
	
	/**
	 * Called by URI /filelist/*
	 * @param uri whole uri since we do not know exactly what will come
	 * @return file list of error
	 */
	protected String getFilelist(Uri uri) {
		// get context for ressouce output
		Context ctx = getContext();

		// check uri
		int matchedUriType = FILE_LIST_MATCHER.match(uri);
		
		// decide what to return depending on uri
		switch(matchedUriType) {
		case URI_FILELIST_ANNOUNCEMENT:
			return getAnnouncementMP3(uri.getPathSegments().get(2));
		case URI_FILELIST_DATA_TRANSFER:
			return ctx.getString(R.string.mp3_data_transfer);
		case URI_FILELIST_INCOMING_DATA:
			return ctx.getString(R.string.mp3_incoming_data);
		case URI_FILELIST_THREAT:
			// get segments
			List<String> segments = uri.getPathSegments();
			int time = Integer.parseInt(segments.get(3));
			return getThreatMP3(segments.get(2), time, segments.get(4), segments.get(5));
		case URI_FILELIST_WHITE_NOISE:
			return getWhiteNoiseMP3(Integer.parseInt(uri.getPathSegments().get(2)));
		default:
			throw new IllegalArgumentException("Unknown file list URI " + uri);
		}
	}
	
	/**
	 * Return announcement MP3 files depending on parameter
	 * @param announcement
	 * @return List of MP3s
	 */
	protected String getAnnouncementMP3(String announcement) {
		// get context for resource output
		Context ctx = getContext();
		// get id from string
		int id = getContext().getResources().getIdentifier("mp3." + announcement, "string", AUTHORITY);

		switch (id) {
		case 0: return " ERROR: String " + announcement + " not found"; // return error
		// special cases: end of phases
		case R.string.mp3_first_phase_ends: return ctx.getString(id) + ',' + ctx.getString(R.string.mp3_second_phase_begins);
		case R.string.mp3_second_phase_ends: return ctx.getString(id) + ',' + ctx.getString(R.string.mp3_third_phase_begins);
		// normal stuff - just return it (relatively dumb, but so what)
		default:
			return ctx.getString(id); // return resource entry
		}
	}

	/**
	 * 
	 * @param time 1-8
	 * @param unconfirmed "unconfirmed" or anything else
	 * @param seriousness "serious" or anything else
	 * @param type "internal", "blue", "red" or "white"
	 * @return List of MP3s
	 */
	protected String getThreatMP3(String unconfirmed, int time, String seriousness, String type) {
		// get context for resource output
		Context ctx = getContext();
		StringBuilder sb = new StringBuilder();
		
		if (unconfirmed.equalsIgnoreCase("unconfirmed")) sb.append(ctx.getString(R.string.mp3_unconfirmed_report)).append(',');
		
		switch(time) {
		case 1:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_1));
			break;
		case 2:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_2));
			break;
		case 3:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_3));
			break;
		case 4:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_4));
			break;
		case 5:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_5));
			break;
		case 6:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_6));
			break;
		case 7:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_7));
			break;
		case 8:
			sb.append(ctx.getString(R.string.mp3_time_t_plus_8));
			break;
		default:
			throw new IllegalArgumentException("time is not 1 - 8");
		}		
		sb.append(",");
		
		// internal/external?
		boolean internal = false;
		boolean serious = false;
		int position = -1;
		if (type.equalsIgnoreCase("internal")) internal = true;
		else if (type.equalsIgnoreCase("blue")) position = R.string.mp3_zone_blue;
		else if (type.equalsIgnoreCase("red")) position = R.string.mp3_zone_red;
		else if (type.equalsIgnoreCase("white")) position = R.string.mp3_zone_white;
		else new IllegalArgumentException("position is not internal, blue, red, or white");
		if (seriousness.equalsIgnoreCase("serious")) serious = true;

		// bow build mp3 list
		if (internal) {
			if (serious) sb.append(ctx.getString(R.string.mp3_serious_internal_threat));
			else sb.append(ctx.getString(R.string.mp3_internal_threat));
		} else {
			// switch by language pattern
			if (FILE_TYPE_ENGLISH) {
				if (serious) sb.append(ctx.getString(R.string.mp3_serious_threat));
				else sb.append(ctx.getString(R.string.mp3_threat));
				sb.append(",").append(ctx.getString(position));
			} else { // german/czech naming scheme
				if (serious) {
					switch(position) {
					case R.string.mp3_zone_blue: sb.append(ctx.getString(R.string.mp3_serious_threat_zone_blue)); break;
					case R.string.mp3_zone_red: sb.append(ctx.getString(R.string.mp3_serious_threat_zone_red)); break;
					case R.string.mp3_zone_white: sb.append(ctx.getString(R.string.mp3_serious_threat_zone_white)); break;
					}
				} else {
					switch(position) {
					case R.string.mp3_zone_blue: sb.append(ctx.getString(R.string.mp3_threat_zone_blue)); break;
					case R.string.mp3_zone_red: sb.append(ctx.getString(R.string.mp3_threat_zone_red)); break;
					case R.string.mp3_zone_white: sb.append(ctx.getString(R.string.mp3_threat_zone_white)); break;
					}
				}
			}
		}

		// main message
		String message = sb.toString();
		
		// clean and but together
		sb = new StringBuilder();

		sb.append(ctx.getString(R.string.mp3_alert)).append(',').append(message).append(',').append(ctx.getString(R.string.mp3_repeat)).append(message);
		
		return sb.toString();
	}

	/**
	 * Return white noise MP3
	 * @param length in seconds
	 * @return List of MP3s
	 */
	protected String getWhiteNoiseMP3(int length) {
		StringBuilder sb = new StringBuilder();
		
		// calculate time of white noise
		sb.append(R.string.mp3_communications_down + "," + R.string.mp3_white_noise + ":").append(length - 2).append("," + R.string.mp3_communications_restored);

		return sb.toString();
	}
	
	/**
	 * Open MP3
	 */
	@Override
	public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
		// sanity checks
		if (mode.contains("w") || mode.contains("+") || !mode.contains("r")) throw new IllegalArgumentException("Illegal access to files.");
		List<String> segments = uri.getPathSegments();
		if (segments.size() != 2) throw new IllegalArgumentException("Illegal uri");
		if (!segments.get(0).equals("mp3")) throw new IllegalArgumentException("Illegal uri");
		
		// get filename
		String filename = filenameOnly(segments.get(1));
		
		// get id from string
		int id = getContext().getResources().getIdentifier(filename, "raw", AUTHORITY);
		if (id == 0) throw new FileNotFoundException("File not found: " + uri); //not found

		// return parcel file descriptor of this element
		return getContext().getResources().openRawResourceFd(id).getParcelFileDescriptor();
	}

	/**
	 * gets filename without extension
	 * @return filename without extension
	 */
	private String filenameOnly(String filename) {
		int dot = filename.lastIndexOf('.');
		return filename.substring(0, dot);
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		// Dummy: do not do anything!
		return 0;
	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		// Dummy: do not do anything!
		return null;
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		// Dummy: do not do anything!
		return 0;
	}
}
